今仔日咱繼續來耍 HTTP/2!
我感覺今仔日這篇欲介紹的物件是誠趣味,共 HTTP/1.1 佮 HTTP/2 的無一致舞甲透透透,毋過其實攏是一寡簡單的 trick 爾爾,無啥物偌複雜的理論。
咱先來餾一下仔 HTTP/2 有啥特性才來開始:
佇 HTTP/1.1 的世界內面,一逝就是一逝,一个請求干焦會有一个 method(GET/POST...)佮一個 path,聽起來誠合理。毋過,HTTP/2 共遐的 request line 攏總會拆做「pseudo-headers」,譬論講 :method
、:path
。問題來囉,既然彼是 header,咱敢會當佇請求內底囥兩擺?
有可能!有寡 server 會接受咱送兩个無仝的 :path
標頭。這个時陣,到底欲用佗一个,就看 server 遐是按怎寫的。若按呢,前台的 server 可能看某乜一个,後台煞看另外一个,按呢就會出代誌矣。
:method GET
:path /good-path
:path /bad-path <-- 凡勢會當用這踅過一寡 WAF
:authority example.com
閣有,咱攏知 Host header 足重要,HTTP/2 共彼升級做 :authority
。毋過,有的時陣(閣再)為著欲相容,Host header 嘛是會當用得。這个時,你若共 :authority
佮 Host
做伙送出去,閣分別指去無仝所在,按呢就趣味矣,予你有機會做 host header attack:
:method GET
:path /
:authority example.com <-- 前端 Server 看這个
Host attacker.com <-- 毋過後端 Server 是會看這个
HTTP/2 有一个 pseudo header 號做 :scheme
,正常狀況下,伊的值愛是 http
抑是 https
。毋過有寡 server 根本無共檢查,隨在你傳,啥物攏收。若閣䢢拄䢢這个 server 會用 :scheme
來鬥出完整的 URL 就會出重耽。
譬論講 PortSwigger 發現 Netlify 就有這个問題。攻擊者會當直接佇 :scheme
內底搢入去一部分的 URL 路徑,予 server 應一个錯誤的轉址,甚至汙染著 cache。
這个例會予 server 產生一个走精的轉址 URL。
:method GET
:path /ffx36.js
:authority start.mozilla.org
:scheme http://start.mozilla.org/xyz? <-- 注意看這个 scheme
Server 收著了後,可能會產生這款的 Location 標頭,共你的 xyz?
鬥佇頭前,應一个按呢的 header:Location: https://start.mozilla.org/xyz?://start.mozilla.org/ffx36.js
若閣較嚴重的,會直接變做 SSRF 攻擊!
佇 HTTP/1.1,標頭名內底袂當有冒號 :
。毋過佇 HTTP/2,一切攏是 binary 格式,有寡 server 會允准囥 :
佇 header name 這款無合理的代誌發生。若閣拄仔好後端 server 會共 HTTP/2 降去 HTTP/1.1,這个冒號就會予伊規个亂去。
這招上適合的目標,佇遮就是 Host
header。主要是 Host
伊本身就會接一个冒號來指定 port,按呢後端 server 看著你注入去的 Host
標頭,就有可能會共冒號後壁的字提㧒捔。
咱會當注一个咱家己的 Host
header,予後端 server 叫是咱欲連入去 psres.net
。
:method GET
:path /
:authority example.com
host: psres.net 443 <-- 注入這个奇怪的標頭名
降做 HTTP/1.1 了後會變做按呢:
GET / HTTP/1.1
Host: example.com
Host: psres.net: 443 <-- 後端 server 可能會先看遮 👀
這个閣較趣味。Apache 的 mod_proxy
捌予人發現一个漏洞,伊予 :method
這个 pseudo header 內底會當有空白字元。這佇 HTTP/1.1 是絕對無可能發生的代誌。這个空白會予降級後的請求,直接隨在咱佇 request line 注入內容。
這有啥物路用?譬論講,前端若有設一寡規則,像講 /admin
路徑袂當入去,咱就有法度共伊踅過去。
這个例直接佇 :method
注入去完整的 HTTP/1.1 請求行,來踅過 /admin
的封鎖。
:method GET /admin HTTP/1.1 <-- 看遮,空白後壁閣有物件
:path /fakepath
:authority psres.net
降級了後請求會變做按呢,後端 server 會直接去處理 /admin
,毋過前端遐無發現這有問題。
GET /admin HTTP/1.1 /fakepath HTTP/1.1
Host: internal-server
古早時的 HTTP/1.1 有一个號做「line folding」的功能,就是會當佇標頭值的中央用「換逝 (\r\n
)+空白」,server 會共伊當做是仝一个標頭。落尾這个功能予人廢掉矣,毋過真濟 server 原仔猶是支援。
GET / HTTP/1.1
Host: example.com
X-Long-Header: foo bar
Connection: close
會使夆變做
GET / HTTP/1.1
Host: example.com
X-Long-Header: foo[\r\n]
[space]bar
Connection: close
啊若拄好 HTTP/2 前端予你送一个用空白做開頭的標頭名,而且後端遐閣支援 line folding,咱就有法度共別个頭(甚至是 server 家己囥入去的內部 header)的值改掉!
像講,若是有一个前端 server 接著請求會囥一个「Request-Id: ID」header 入去,才閣送去後端,咱佇遮是會當共 Request-Id
這个標頭改去的。
:method GET
:path /
:authority redacted.net
[space]poison x <-- 這个標頭用空白做開頭
user-agent burp
降級了後,因為 poison
是用空白開頭,後端 server 會想講伊是頂頭彼个 Request-Id
標頭的延伸,共 poison: x
接佇伊後壁,造成竄改。
HTTP/1.1 200 OK
...
Request-Id: 1-602d2c4b-7c9a1f0f7 poison: x <-- 成功改去!
咱明仔載會來翻頭講 HTTP/1.1,著啦,就是今年拄出,上欻的 HTTP/1.1 must die: the desync endgame!
我感覺咱講 HTTP 的物件已經講三工講甲誠濟矣,恁看了敢會有淡薄仔siān矣 :P